//
//  API_AsyncSequence_Demo3VC.swift
//  APSwift
//
//  Created by jianbo.pei on 2024/8/16.
//

import UIKit

class API_AsyncSequence_Demo3VC: UIViewController {
    
    // UI 组件
    private lazy var tapButton: UIButton = {
        let button = UIButton(type: .system)
        button.setTitle("点击我", for: .normal)
        button.titleLabel?.font = UIFont.systemFont(ofSize: 18)
        button.backgroundColor = UIColor.systemBlue
        button.setTitleColor(.white, for: .normal)
        button.layer.cornerRadius = 8
        button.translatesAutoresizingMaskIntoConstraints = false
        return button
    }()
    
    private lazy var resetButton: UIButton = {
        let button = UIButton(type: .system)
        button.setTitle("重置计数", for: .normal)
        button.titleLabel?.font = UIFont.systemFont(ofSize: 16)
        button.backgroundColor = UIColor.systemOrange
        button.setTitleColor(.white, for: .normal)
        button.layer.cornerRadius = 8
        button.translatesAutoresizingMaskIntoConstraints = false
        return button
    }()
    
    private lazy var statusLabel: UILabel = {
        let label = UILabel()
        label.text = "等待用户点击..."
        label.textAlignment = .center
        label.font = UIFont.systemFont(ofSize: 16)
        label.numberOfLines = 0
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()
    
    private lazy var logTextView: UITextView = {
        let textView = UITextView()
        textView.isEditable = false
        textView.font = UIFont.monospacedSystemFont(ofSize: 14, weight: .regular)
        textView.backgroundColor = UIColor.systemGray6
        textView.layer.cornerRadius = 8
        textView.translatesAutoresizingMaskIntoConstraints = false
        return textView
    }()
    
    // 按钮点击事件流
    private var buttonTapStream: ButtonTapStream?
    private var tapTask: Task<Void, Never>?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupUI()
        setupButtonTapStream()
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        // 取消异步任务
        tapTask?.cancel()
    }
    
    private func setupUI() {
        view.backgroundColor = .white
        title = "用户界面事件流示例"
        
        view.addSubview(tapButton)
        view.addSubview(resetButton)
        view.addSubview(statusLabel)
        view.addSubview(logTextView)
        
        NSLayoutConstraint.activate([
            tapButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            tapButton.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 50),
            tapButton.widthAnchor.constraint(equalToConstant: 200),
            tapButton.heightAnchor.constraint(equalToConstant: 50),
            
            resetButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            resetButton.topAnchor.constraint(equalTo: tapButton.bottomAnchor, constant: 20),
            resetButton.widthAnchor.constraint(equalToConstant: 120),
            resetButton.heightAnchor.constraint(equalToConstant: 40),
            
            statusLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
            statusLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20),
            statusLabel.topAnchor.constraint(equalTo: resetButton.bottomAnchor, constant: 30),
            
            logTextView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
            logTextView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20),
            logTextView.topAnchor.constraint(equalTo: statusLabel.bottomAnchor, constant: 20),
            logTextView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -20)
        ])
        
        // 添加按钮事件
        resetButton.addTarget(self, action: #selector(resetButtonTapped), for: .touchUpInside)
    }
    
    private func setupButtonTapStream() {
        // 创建按钮点击事件流
        buttonTapStream = ButtonTapStream(button: tapButton)
        
        // 开始监听按钮点击事件
        tapTask = Task { [weak self] in
            guard let self = self, let stream = self.buttonTapStream else { return }
            
            var tapCount = 0
            
            do {
                for try await tapEvent in stream {
                    // 检查任务是否被取消
                    if Task.isCancelled { break }
                    
                    tapCount += 1
                    
                    await MainActor.run {
                        self.handleButtonTap(count: tapCount, event: tapEvent)
                    }
                }
            } catch {
                await MainActor.run {
                    self.appendLog("事件流错误: \(error)")
                }
            }
        }
    }
    
    private func handleButtonTap(count: Int, event: ButtonTapEvent) {
        let timestamp = DateFormatter.localizedString(from: event.timestamp, dateStyle: .none, timeStyle: .medium)
        
        statusLabel.text = "按钮已被点击 \(count) 次"
        
        let logMessage = "[\(timestamp)] 第 \(count) 次点击 - 位置: (\(Int(event.location.x)), \(Int(event.location.y)))"
        appendLog(logMessage)
        
        // 根据点击次数显示不同的反馈
        if count % 10 == 0 {
            showSpecialFeedback(for: count)
        }
    }
    
    private func showSpecialFeedback(for count: Int) {
        let alert = UIAlertController(
            title: "里程碑！",
            message: "您已经点击了 \(count) 次！",
            preferredStyle: .alert
        )
        alert.addAction(UIAlertAction(title: "继续", style: .default))
        present(alert, animated: true)
    }
    
    private func appendLog(_ message: String) {
        let currentText = logTextView.text ?? ""
        logTextView.text = currentText + message + "\n"
        
        // 滚动到底部
        let bottom = NSMakeRange(logTextView.text.count - 1, 1)
        logTextView.scrollRangeToVisible(bottom)
    }
    
    @objc private func resetButtonTapped() {
        statusLabel.text = "计数已重置，等待用户点击..."
        logTextView.text = ""
        
        // 重新设置按钮点击流
        tapTask?.cancel()
        setupButtonTapStream()
    }
}

// MARK: - 按钮点击事件数据模型
struct ButtonTapEvent {
    let timestamp: Date
    let location: CGPoint
    let buttonTitle: String?
}

// MARK: - 按钮点击事件流
struct ButtonTapStream: AsyncSequence {
    typealias Element = ButtonTapEvent
    
    private let button: UIButton
    
    init(button: UIButton) {
        self.button = button
    }
    
    func makeAsyncIterator() -> ButtonTapAsyncIterator {
        return ButtonTapAsyncIterator(button: button)
    }
}

// MARK: - 按钮点击异步迭代器
struct ButtonTapAsyncIterator: AsyncIteratorProtocol {
    typealias Element = ButtonTapEvent
    
    private let button: UIButton
    private let continuation: AsyncStream<ButtonTapEvent>.Continuation
    private let stream: AsyncStream<ButtonTapEvent>
    
    init(button: UIButton) {
        self.button = button
        
        var continuation: AsyncStream<ButtonTapEvent>.Continuation!
        self.stream = AsyncStream<ButtonTapEvent> { cont in
            continuation = cont
        }
        self.continuation = continuation
        
        // 设置按钮点击监听
        setupButtonTarget()
    }
    
    private func setupButtonTarget() {
        // 创建一个目标-动作对象来处理按钮点击
        let target = ButtonTapTarget { [weak button] in
            guard let button = button else { return }
            
            let event = ButtonTapEvent(
                timestamp: Date(),
                location: CGPoint(x: button.frame.midX, y: button.frame.midY),
                buttonTitle: button.title(for: .normal)
            )
            
            continuation.yield(event)
        }
        
        // 将目标对象关联到按钮
        objc_setAssociatedObject(
            button,
            &ButtonTapTarget.associatedObjectKey,
            target,
            .OBJC_ASSOCIATION_RETAIN_NONATOMIC
        )
        
        button.addTarget(target, action: #selector(ButtonTapTarget.buttonTapped), for: .touchUpInside)
    }
    
    mutating func next() async throws -> ButtonTapEvent? {
        for await event in stream {
            return event
        }
        return nil
    }
}

// MARK: - 按钮点击目标类
private class ButtonTapTarget {
    static var associatedObjectKey: UInt8 = 0
    
    private let onTap: () -> Void
    
    init(onTap: @escaping () -> Void) {
        self.onTap = onTap
    }
    
    @objc func buttonTapped() {
        onTap()
    }
}
